home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / bash / bash_108 / bash-108.zoo / src / subst.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-12  |  68.2 KB  |  2,811 lines

  1. /* substitutions.c -- The part of the shell that does parameter,
  2.    command, and globbing substitutions. */
  3.  
  4. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  5.  
  6. This file is part of GNU Bash, the Bourne Again SHell.
  7.  
  8. Bash is free software; you can redistribute it and/or modify it under
  9. the terms of the GNU General Public License as published by the Free
  10. Software Foundation; either version 1, or (at your option) any later
  11. version.
  12.  
  13. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  14. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License along
  19. with Bash; see the file COPYING.  If not, write to the Free Software
  20. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  21.  
  22. #include <stdio.h>
  23. #include <pwd.h>
  24. #include <fcntl.h>
  25. #include <signal.h>
  26. #include "shell.h"
  27. #include "flags.h"
  28. #include "alias.h"
  29. #include "jobs.h"
  30. #include <readline/history.h>
  31.  
  32. /* The size that strings change by. */
  33. #define DEFAULT_ARRAY_SIZE 512
  34.  
  35. /* Some forward declarations. */
  36.  
  37. extern WORD_LIST *expand_string (), *expand_word (), *list_string ();
  38. extern char *string_list ();
  39. extern WORD_DESC *make_word ();
  40. extern WORD_DESC *copy_word ();
  41. extern WORD_LIST *copy_word_list();
  42. static WORD_LIST *expand_string_internal ();
  43.  
  44. /* **************************************************************** */
  45. /*                                    */
  46. /*            Utility Functions                */
  47. /*                                    */
  48. /* **************************************************************** */
  49.  
  50.  
  51. /* Cons a new string from STRING starting at START and ending at END,
  52.    not including END. */
  53. char *
  54. substring (string, start, end)
  55.      char *string;
  56.      int start, end;
  57. {
  58.   register int len = end - start;
  59.   register char *result = (char *)xmalloc (len + 1);
  60.  
  61.   strncpy (result, string + start, len);
  62.   result[len] = '\0';
  63.   return (result);
  64. }
  65.  
  66. /* Just like string_extract, but doesn't hack backslashes or any of
  67.    that other stuff. */
  68. char *
  69. string_extract_verbatim (string, sindex, charlist)
  70.      char *string, *charlist;
  71.      int *sindex;
  72. {
  73.   register int i = *sindex;
  74.   int c;
  75.   char *temp;
  76.  
  77.   while ((c = string[i]) && (!member (c, charlist))) i++;
  78.   temp = (char *)xmalloc (1 + (i - *sindex));
  79.   strncpy (temp, string + (*sindex), i - (*sindex));
  80.   temp[i - (*sindex)] = '\0';
  81.   *sindex = i;
  82.   return (temp);
  83. }
  84.  
  85. /* Extract a substring from STRING, starting at SINDEX and ending with
  86.    one of the characters in CHARLIST.  Don't make the ending character
  87.    part of the string.  Leave SINDEX pointing at the ending character.
  88.    Understand about backslashes in the string. */
  89. char *
  90. string_extract (string, sindex, charlist)
  91.      char *string, *charlist;
  92.      int *sindex;
  93. {
  94.   register int c, i = *sindex;
  95.   char *temp;
  96.  
  97.   while (c = string[i]) {
  98.     if (c == '\\')
  99.       if (string[i + 1])
  100.     i++;
  101.       else
  102.     break;
  103.     else
  104.       if (member (c, charlist))
  105.     break;
  106.     i++;
  107.   }
  108.   temp = (char *)xmalloc (1 + (i - *sindex));
  109.   strncpy (temp, string + (*sindex), i - (*sindex));
  110.   temp[i - (*sindex)] = '\0';
  111.   *sindex = i;
  112.   return (temp);
  113. }
  114.  
  115. /* Remove backslashes which are quoting backquotes from STRING.  Modifies
  116.    STRING, and returns a pointer to it. */
  117. char *
  118. de_backslash (string)
  119.      char *string;
  120. {
  121.   register int i, l = strlen (string);
  122.  
  123.   for (i = 0; i < l; i++)
  124.     if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
  125.                   string[i + 1] == '$'))
  126.       strcpy (&string[i], &string[i + 1]);
  127.   return (string);
  128. }
  129.  
  130. /* Replace instances of \! in a string with !. */
  131. void
  132. unquote_bang (string)
  133.      char *string;
  134. {
  135.   register int i, j;
  136.   register char *temp = (char *)alloca (1 + strlen (string));
  137.  
  138.   for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
  139.     {
  140.       if (string[i] == '\\' && string[i + 1] == '!')
  141.     {
  142.       temp[j] = '!';
  143.       i++;
  144.     }
  145.     }
  146.   strcpy (string, temp);
  147. }
  148.  
  149. /* Extract the $( construct in STRING, and return a new string.
  150.    Start extracting at (SINDEX) as if we had just seen "$(".
  151.    Make (SINDEX) get the position just after the matching ")". */
  152. char *
  153. extract_command_subst (string, sindex)
  154.      char *string;
  155.      int *sindex;
  156. {
  157.   char *extract_delimited_string ();
  158.  
  159.   return (extract_delimited_string (string, sindex, "$(", "(", ")"));
  160. }
  161.  
  162. /* Extract the $[ construct in STRING, and return a new string.
  163.    Start extracting at (SINDEX) as if we had just seen "$[".
  164.    Make (SINDEX) get the position just after the matching "]".
  165.  
  166.    Strictly speaking, according to the letter of POSIX.2, arithmetic
  167.    substitutions cannot be nested.  This code allows nesting however,
  168.    and it is fully implemented. */
  169. char *
  170. extract_arithmetic_subst (string, sindex)
  171.      char *string;
  172.      int *sindex;
  173. {
  174.   char *extract_delimited_string ();
  175.  
  176.   return (extract_delimited_string (string, sindex, "$[", "[", "]"));
  177. }
  178.  
  179. /* Extract and create a new string from the contents of STRING, a
  180.    character string delimited with OPENER and CLOSER.  SINDEX is
  181.    the address of an int describing the current offset in STRING;
  182.    it should point to just after the first OPENER found.  On exit,
  183.    SINDEX gets the position just after the matching CLOSER.  If
  184.    OPENER is more than a single character, ALT_OPENER, if non-null,
  185.    contains a character string that can also match CLOSE and thus
  186.    needs to be skipped. */
  187. char *
  188. extract_delimited_string (string, sindex, opener, alt_opener, closer)
  189.      char *string;
  190.      int *sindex;
  191.      char *opener, *alt_opener, *closer;
  192. {
  193.   register int i, c, l;
  194.   int pass_character, nesting_level;
  195.   int delimiter, delimited_nesting_level;
  196.   int len_closer, len_opener, len_alt_opener;
  197.   char *result;
  198.  
  199.   len_opener = strlen (opener);
  200.   len_alt_opener = alt_opener ? strlen (alt_opener) : 0;
  201.   len_closer = strlen (closer);
  202.  
  203.   pass_character = delimiter = delimited_nesting_level = 0;
  204.  
  205.   nesting_level = 1;
  206.  
  207.   for (i = *sindex; c = string[i]; i++)
  208.     {
  209.       if (pass_character)
  210.     {
  211.       pass_character = 0;
  212.       continue;
  213.     }
  214.  
  215.       if (c == '\\')
  216.     {
  217.       if ((delimiter == '"') &&
  218.           (member (string[i + 1], slashify_in_quotes)))
  219.         {
  220.         pass_next_character:
  221.           pass_character++;
  222.           continue;
  223.         }
  224.     }
  225.  
  226.       if (!delimiter || delimiter == '"')
  227.     {
  228.       if (strncmp (string + i, opener, len_opener) == 0)
  229.         {
  230.           if (!delimiter)
  231.         nesting_level++;
  232.           else
  233.         delimited_nesting_level++;
  234.  
  235.           i += len_opener - 1;
  236.           continue;
  237.         }
  238.  
  239.       if (strncmp (string + i, alt_opener, len_alt_opener) == 0)
  240.         {
  241.           if (!delimiter)
  242.         nesting_level++;
  243.           else
  244.         delimited_nesting_level++;
  245.  
  246.           i += len_alt_opener - 1;
  247.           continue;
  248.         }
  249.  
  250.       if (strncmp (string + i, closer, len_closer) == 0)
  251.         {
  252.           i += len_closer - 1;
  253.  
  254.           if (delimiter && delimited_nesting_level)
  255.         delimited_nesting_level--;
  256.  
  257.           if (!delimiter)
  258.         {
  259.           nesting_level--;
  260.           if (nesting_level == 0)
  261.             break;
  262.         }
  263.         }
  264.     }
  265.  
  266.       if (delimiter)
  267.     {
  268.       if (c == delimiter || delimiter == '\\')
  269.         delimiter = 0;
  270.       continue;
  271.     }
  272.       else
  273.     {
  274.       if (c == '"' || c == '\'' || c == '\\')
  275.         delimiter = c;
  276.     }
  277.     }
  278.  
  279.   l = i - *sindex;
  280.   result = (char *)xmalloc (1 + l);
  281.   strncpy (result, &string[*sindex], l);
  282.   result[l] = '\0';
  283.   *sindex = i;
  284.  
  285.   if (!c && (delimiter || nesting_level))
  286.     {
  287.       report_error ("Bad substitution: `%s%s'", opener, result);
  288.       free (result);
  289.       longjmp (top_level, DISCARD);
  290.     }
  291.   return (result);
  292. }
  293.  
  294. /* An artifact for extracting the contents of a quoted string.  Since the
  295.    string is about to be evaluated, we pass everything through, and only
  296.    strip backslash before backslash or quote. */
  297. /* Changed to pass double quotes in backquotes in double quotes through as
  298.    well.  What a kludge.  It's for echo "`(cd "$HOME" ; echo $PWD)`",
  299.    which sh handles with no errors. */
  300. char *
  301. string_extract_double_quoted (string, sindex)
  302.      char *string;
  303.      int *sindex;
  304. {
  305.   register int c, j, i;
  306.   char *temp = (char *)xmalloc (1 + strlen (string + (*sindex)));
  307.   int delimiter = '"';
  308.   int last_was_backslash = 0;
  309.  
  310.   for (j = 0, i = *sindex; ((c = string[i]) && (c != '"')); i++)
  311.     {
  312.       /* Trap backslases that are quoting double quotes; strip these
  313.      backslashes and do not allow the quotes to terminate the
  314.      string prematurely.  Pass other backslashes through; they,
  315.      and the characters they protect, are taken care of later.
  316.      The Bourne shell quoting rules are baroque! */
  317.       if (c == '\\')
  318.     {
  319.       c = string[++i];
  320.  
  321.       /* Remove backslashes protecting double quotes. */
  322.       if (c != '"')
  323.         temp[j++] = '\\';
  324.  
  325.       last_was_backslash = 1;
  326.     }
  327.       temp[j++] = c;
  328.  
  329.       /* Interpret matched backquotes, passing double quotes through
  330.      verbatim.  Do this iff the opening backquote is not escaped
  331.      with a backslash. */
  332.       if (!last_was_backslash && c == '`')
  333.     {
  334.       while ((c = string[++i]) != '`' && c)
  335.         {
  336.           temp[j++] = c;
  337.  
  338.           /* Quoted backquotes are passed through, so we must implement
  339.          pass-next-character-verbatim semantics here, and avoid the
  340.          check above.  Handle unexpected end of string by breaking
  341.          out of the loop. */
  342.           if (c == '\\')
  343.         {
  344.           c = string[++i];
  345.  
  346.           temp[j++] = c;
  347.  
  348.           /* If we have unexpectedly reached the end of the string,
  349.              quit processing. */
  350.           if (!c)
  351.             break;
  352.         }
  353.         }
  354.       temp[j++] = c;
  355.     }
  356.  
  357.       /* Pass everything between `$(' and the matching `)' through verbatim. */
  358.       if (!last_was_backslash && c == '$' && string[i + 1] == '(')
  359.     {
  360.       register int t;
  361.       int si;
  362.       char *ret;
  363.  
  364.       si = i + 2;
  365.       ret = extract_delimited_string (string, &si, "$(", "(", ")");
  366.  
  367.       /* The '$' has already added to TEMP above. */
  368.       temp[j++] = '(';
  369.  
  370.       for (t = 0; ret[t]; t++)
  371.         temp[j++] = ret[t];
  372.  
  373.       i = si;
  374.       temp[j++] = string[i];
  375.     }
  376.  
  377.       /* Last character processed is no longer a backslash. */
  378.       last_was_backslash = 0;
  379.     }
  380.   temp[j] = '\0';
  381.   *sindex = i;
  382.   return (temp);
  383. }
  384.  
  385. /* Extract the name of the variable to bind to from the assignment string. */
  386. char *
  387. assignment_name (string)
  388.      char *string;
  389. {
  390.   int offset = assignment (string);
  391.   char *temp;
  392.   if (!offset) return (char *)NULL;
  393.   temp = (char *)xmalloc (offset + 1);
  394.   strncpy (temp, string, offset);
  395.   temp[offset] = '\0';
  396.   return (temp);
  397. }
  398.  
  399. /* Return a single string of all the words in LIST. */
  400. char *
  401. string_list (list)
  402.      WORD_LIST *list;
  403. {
  404.   char *result = (char *)NULL;
  405.  
  406.   while (list)
  407.     {
  408.       if (!result)
  409.     result = savestring ("");
  410.  
  411.       result =
  412.     (char *)xrealloc (result, 3 + strlen (result) + strlen (list->word->word));
  413.       strcat (result, list->word->word);
  414.       if (list->next) strcat (result, " ");
  415.       list = list->next;
  416.     }
  417.   return (result);
  418. }
  419.  
  420. /* Return a single string of all the words present in LIST, obeying the
  421.    quoting rules for "$*", to wit: (P1003.2, draft 9, 3.6.2, "If the
  422.    expansion [of $*] appears within double quotes, it expands to a single
  423.    word with the value of each parameter separated by the first character
  424.    of the IFS variable, or by a <space> if IFS is unset or null."
  425.  
  426.    This would ideally be part of string_list, but the whole world uses
  427.    that, and it seems easier to make a new function rather than change
  428.    the declaration of the old one everywhere. */
  429. char *
  430. string_list_dollar_star (list)
  431.      WORD_LIST *list;
  432. {
  433.   char *result = (char *)NULL;
  434.   char *ifs = get_string_value ("IFS");
  435.   char sep[2];
  436.  
  437.   if (!ifs || !*ifs)
  438.     sep[0] = ' ';
  439.   else
  440.     sep[0] = *ifs;
  441.   sep[1] = '\0';
  442.  
  443.   while (list)
  444.     {
  445.       if (!result)
  446.     result = savestring ("");
  447.  
  448.       result = (char *)
  449.     xrealloc (result, 3 + strlen (result) + strlen (list->word->word));
  450.       strcat (result, list->word->word);
  451.  
  452.       if (list->next)
  453.     strcat (result, sep);
  454.  
  455.       list = list->next;
  456.     }
  457.   return (result);
  458. }
  459.  
  460. /* Return the list of words present in STRING.  Separate the string into
  461.    words at any of the characters found in SEPARATORS.  If QUOTED is
  462.    non-zero then word in the list will have its quoted flag set, otherwise
  463.    the quoted flag is left as make_word () deemed fit.
  464.  
  465.    This obeys the P1003.2 draft 9 word splitting semantics, to wit:  if
  466.    `separators' is exactly <space><tab><newline>, or if it is "" (meaning
  467.     that IFS is unset) then the splitting algorithm is that of the
  468.    Bourne shell, which treats any sequence of characters from `separators'
  469.    as a delimiter.  If not, Korn shell/AWK behavior is assumed, and each
  470.    occurrence of a character from IFS is a delimiter.  */
  471.  
  472. /* BEWARE!  list_string strips null arguments.  Don't call it twice and
  473.    expect to have "" preserved! */
  474.  
  475. /* Is C a quoted NULL character? */
  476. #define QUOTED_NULL(c) ((unsigned char)(c) == (unsigned char)0x80)
  477.  
  478. /* Perform quoted null character removal on STRING. */
  479. void
  480. remove_quoted_nulls (string)
  481.      char *string;
  482. {
  483.   register char *s;
  484.  
  485.   for (s = string; s && *s; s++)
  486.     {
  487.       if (QUOTED_NULL (*s))
  488.     {
  489.       strcpy (s, s + 1);
  490.       s--;
  491.     }
  492.     }
  493. }
  494.  
  495. /* This performs word splitting and quote removal on STRING. */
  496. WORD_LIST *
  497. list_string (string, separators, quoted)
  498.      register char *string, *separators;
  499.      int quoted;
  500. {
  501.   WORD_LIST *result = (WORD_LIST *)NULL;
  502.   char *current_word = (char *)NULL;
  503.   int sindex = 0;
  504.   int do_sequences;
  505.  
  506.   do_sequences =  separators && *separators && (strcmp (separators, " \t\n") == 0);
  507.  
  508.   while (string[sindex] &&
  509.      (current_word =
  510.       string_extract_verbatim (string, &sindex, separators)))
  511.     {
  512.       /* If we have something, then add it regardless. */
  513.       if (strlen (current_word))
  514.     {
  515.       register char *temp_string;
  516.  
  517.       /* Perform quote removal on the current word. */
  518.        for (temp_string = current_word; *temp_string; temp_string++)
  519.         if (QUOTED_NULL (*temp_string))
  520.           {
  521.         strcpy (temp_string, temp_string + 1);
  522.         temp_string--;
  523.           }
  524.  
  525.       result = make_word_list (make_word (current_word), result);
  526.       if (quoted)
  527.         result->word->quoted++;
  528.     }
  529.       /* If we're not doing sequences, then add a quoted null argument. */
  530.       /* XXX - I've forgotten why `quoted' was here; make a note when I
  531.      remember. */
  532.       else if (!do_sequences /* && quoted */)
  533.     {
  534.       result = make_word_list (make_word (""), result);
  535.       result->word->quoted++;
  536.     }
  537.       free (current_word);
  538.       if (string[sindex]) sindex++;
  539.     }
  540.   return (WORD_LIST *)reverse_list (result);
  541. }
  542.  
  543. /* Given STRING, an assignment string, get the value of the right side
  544.    of the `=', and bind it to the left side.  If EXPAND is true, then
  545.    perform parameter expansion, command substitution, and arithmetic
  546.    expansion on the right-hand side.  Perform tilde expansion in any
  547.    case.  Do not perform word splitting on the result of expansion. */
  548. do_assignment_internal (string, expand)
  549.      char *string;
  550.      int expand;
  551. {
  552.   int offset = assignment (string);
  553.   char *name = savestring (string);
  554.   char *value = (char *)NULL;
  555.   SHELL_VAR *entry = (SHELL_VAR *)NULL;
  556.  
  557.   if (name[offset] == '=')
  558.     {
  559.       char *temp, *tilde_expand (), *string_list ();
  560.       WORD_LIST *list, *expand_string_unsplit ();
  561.  
  562.       name[offset] = 0;
  563.       temp = name + offset + 1;
  564.       temp = tilde_expand (temp);
  565.  
  566.       if (expand)
  567.     {
  568.       list = expand_string_unsplit (temp, 0);
  569.       if (list)
  570.         {
  571.           value = string_list (list);
  572.           dispose_words (list);
  573.         }
  574.       free (temp);
  575.     }
  576.       else
  577.     value = temp;
  578.     }
  579.  
  580.   if (!value)
  581.     value = savestring ("");
  582.  
  583.   entry = bind_variable (name, value);
  584.  
  585.   if (echo_command_at_execute)
  586.     {
  587.       extern char *indirection_level_string ();
  588.       fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value);
  589.     }
  590.  
  591.   /* Yes, here is where the special shell variables get tested for.
  592.      Don't ask me, I just work here.  This is really stupid.  I would
  593.      swear, but I've decided that that is an impolite thing to do in
  594.      source that is to be distributed around the net, even if this code
  595.      is totally brain-damaged. */
  596.  
  597.   /* if (strcmp (name, "PATH") == 0) Yeeecchhh!!!*/
  598.   stupidly_hack_special_variables (name);
  599.  
  600.   if (entry)
  601.     entry->attributes &= ~att_invisible;
  602.   if (value)
  603.     free (value);
  604.   free (name);
  605. }
  606.  
  607. /* Perform the assignment statement in STRING, and expand the right side
  608.    by doing command and parameter expansion. */
  609. do_assignment (string)
  610.      char *string;
  611. {
  612.   do_assignment_internal (string, 1);
  613. }
  614.  
  615. /* Given STRING, an assignment string, get the value of the right side
  616.    of the `=', and bind it to the left side.  Do not do command and
  617.    parameter substitution on the right hand side.  This is called from
  618.    set_or_show_attributes() in builtins.c, and when this is called,
  619.    the rhs has already been expanded once. */
  620.  
  621. do_assignment_no_expand (string)
  622.      char *string;
  623. {
  624.   do_assignment_internal (string, 0);
  625. }
  626.  
  627. /* Most of the substitutions must be done in parallel.  In order
  628.    to avoid using tons of unclear goto's, I have some functions
  629.    for manipulating malloc'ed strings.  They all take INDEX, a
  630.    pointer to an integer which is the offset into the string
  631.    where manipulation is taking place.  They also take SIZE, a
  632.    pointer to an integer which is the current length of the
  633.    character array for this string. */
  634.  
  635. /* Append SOURCE to TARGET at INDEX.  SIZE is the current amount
  636.    of space allocated to TARGET.  SOURCE can be NULL, in which
  637.    case nothing happens.  Gets rid of SOURCE by free ()ing it.
  638.    Returns TARGET in case the location has changed. */
  639. char *
  640. sub_append_string (source, target, index, size)
  641.      char *source, *target;
  642.      int *index, *size;
  643. {
  644.   if (source)
  645.     {
  646.       while (strlen (source) >= (*size - *index))
  647.     target = (char *)xrealloc (target, *size += DEFAULT_ARRAY_SIZE);
  648.  
  649.       strcat (target, source);
  650.       *index += strlen (source);
  651.  
  652.       free (source);
  653.     }
  654.   return (target);
  655. }
  656.  
  657. /* Append the textual representation of NUMBER to TARGET.
  658.    INDEX and SIZE are as in SUB_APPEND_STRING. */
  659. char *
  660. sub_append_number (number, target, index, size)
  661.      int number, *index, *size;
  662.      char *target;
  663. {
  664.   char *temp = (char *)xmalloc (10);
  665.   sprintf (temp, "%d", number);
  666.   return (sub_append_string (temp, target, index, size));
  667. }
  668.  
  669. /* Return the word list that corresponds to `$*'. */
  670. WORD_LIST *
  671. list_rest_of_args ()
  672. {
  673.   register WORD_LIST *list = (WORD_LIST *)NULL;
  674.   register WORD_LIST *args = rest_of_args;
  675.   int i;
  676.  
  677.   for (i = 1; i < 10; i++)
  678.     if (dollar_vars[i])
  679.       list = make_word_list (make_word (dollar_vars[i]), list);
  680.   while (args)
  681.     {
  682.       list = make_word_list (make_word (args->word->word), list);
  683.       args = args->next;
  684.     }
  685.   return ((WORD_LIST *)reverse_list (list));
  686. }
  687.  
  688. /* Make a single large string out of the dollar digit variables,
  689.    and the rest_of_args.  If DOLLAR_STAR is 1, then obey the special
  690.    case of "$*" with respect to IFS. */
  691. char *
  692. string_rest_of_args (dollar_star)
  693.      int dollar_star;
  694. {
  695.   register WORD_LIST *list = list_rest_of_args ();
  696.   char *string;
  697.  
  698.   if (!dollar_star)
  699.     string = string_list (list);
  700.   else
  701.     string = string_list_dollar_star (list);
  702.  
  703.   dispose_words (list);
  704.   return (string);
  705. }
  706.  
  707. /***************************************************
  708.  *                           *
  709.  *    Functions to expand a string           *
  710.  *                           *
  711.  ***************************************************/
  712.  
  713. /* Perform parameter expansion, command substitution, and arithmetic
  714.    expansion on STRING, as if it were a word.  Leave the result quoted. */
  715. static WORD_LIST *
  716. expand_string_internal (string, quoted)
  717.      char *string;
  718.      int quoted;
  719. {
  720.   WORD_DESC *make_word (), *temp = make_word (string);
  721.   WORD_LIST *tresult, *expand_word_internal ();
  722.  
  723.   tresult  = expand_word_internal (temp, quoted, (int *)NULL, (int *)NULL);
  724.   dispose_word (temp);
  725.   return (tresult);
  726. }
  727.  
  728. /* Expand STRING by performing parameter expansion, command substitution,
  729.    and arithmetic expansion.  Dequote the resulting WORD_LIST before
  730.    returning it, but do not perform word splitting.  The call to
  731.    remove_quoted_nulls () is in here because word splitting normally
  732.    takes care of quote removal. */
  733. WORD_LIST *
  734. expand_string_unsplit (string, quoted)
  735.      char *string;
  736.      int quoted;
  737. {
  738.   WORD_LIST *value = expand_string_internal (string, quoted);
  739.  
  740.   if (value && value->word)
  741.     remove_quoted_nulls (value->word->word);
  742.  
  743.   dequote (value);
  744.   return (value);
  745. }
  746.  
  747. /* Expand STRING just as if you were expanding a word.  This also returns
  748.    a list of words.  Note that filename globbing is *NOT* done for word
  749.    or string expansion, just when the shell is expanding a command.  This
  750.    does parameter expansion, command substitution, arithmetic expansion,
  751.    and word splitting.  Dequote the resultant WORD_LIST before returning. */
  752. WORD_LIST *
  753. expand_string (string, quoted)
  754.      char *string;
  755.      int quoted;
  756. {
  757.   WORD_LIST *value = expand_string_internal (string, quoted);
  758.   WORD_LIST *result, *word_list_split ();
  759.  
  760.   result = word_list_split (value);
  761.   dispose_words (value);
  762.   if (result)
  763.     dequote (result);
  764.   return (result);
  765. }
  766.  
  767. /* Expand STRING just as if you were expanding a word, but do not dequote
  768.    the resultant WORD_LIST.  This is called only from within this file,
  769.    and is used to correctly preserve quoted characters when expanding
  770.    things like ${1+"$@"}.  This does parameter expansion, command
  771.    subsitution, arithmetic expansion, and word splitting. */
  772. static WORD_LIST *
  773. expand_string_leave_quoted (string, quoted)
  774.      char *string;
  775.      int quoted;
  776. {
  777.   WORD_LIST *tlist  = expand_string_internal (string, quoted);
  778.   WORD_LIST *tresult, *word_list_split ();
  779.  
  780.   tresult = word_list_split (tlist);
  781.   dispose_words (tlist);
  782.   return (tresult);
  783. }
  784.  
  785. /***************************************************
  786.  *                           *
  787.  *    Functions to handle quoting chars       *
  788.  *                           *
  789.  ***************************************************/
  790.  
  791. /* I'm going to have to rewrite expansion because filename globbing is
  792.    beginning to make the entire arrangement ugly.  I'll do this soon. */
  793. dequote (list)
  794.      register WORD_LIST *list;
  795. {
  796.   register char *s;
  797.  
  798.   while (list)
  799.     {
  800.       s = list->word->word;
  801.       dequote_string (s);
  802.       list = list->next;
  803.     }
  804. }
  805.  
  806. /* How to quote and dequote the character C. */
  807. #define QUOTE_CHAR(c)    ((unsigned char)(c) | 0x80)
  808. #define DEQUOTE_CHAR(c) ((unsigned char)(c) & 0x7f)
  809.  
  810. /* Quote the string s. */
  811. quote_string (s)
  812.      char *s;
  813. {
  814.   register unsigned char *t = (unsigned char *) s;
  815.  
  816.   for ( ; t && *t ; t++)
  817.     *t |= 0x80;
  818. }
  819.  
  820. /* De-quoted quoted characters in string s. */
  821. dequote_string (s)
  822.      char *s;
  823. {
  824.   register unsigned char *t = (unsigned char *) s;
  825.  
  826.   for ( ; t && *t; t++)
  827.     *t &= 0x7f;
  828. }
  829.  
  830. /* Quote the entire WORD_LIST list. */
  831. quote_list (list)
  832.      WORD_LIST *list;
  833. {
  834.   register WORD_LIST *w;
  835.  
  836.   for (w = list; w; w = w->next)
  837.     {
  838.       quote_string (w->word->word);
  839.       w->word->quoted = 1;
  840.     }
  841. }
  842.  
  843.  
  844. /* **************************************************************** */
  845. /*                                                                  */
  846. /*                  Functions for Removing Patterns                 */
  847. /*                                                                  */
  848. /* **************************************************************** */
  849.  
  850. /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
  851.    can have one of 4 values:
  852.     RP_LONG_LEFT    remove longest matching portion at start of PARAM
  853.     RP_SHORT_LEFT    remove shortest matching portion at start of PARAM
  854.     RP_LONG_RIGHT    remove longest matching portion at end of PARAM
  855.     RP_SHORT_RIGHT    remove shortest matching portion at end of PARAM
  856. */
  857.  
  858. #define RP_LONG_LEFT    1
  859. #define RP_SHORT_LEFT    2
  860. #define RP_LONG_RIGHT    3
  861. #define RP_SHORT_RIGHT    4
  862.  
  863. static char *
  864. remove_pattern (param, pattern, op)
  865.      char *param, *pattern;
  866.      int op;
  867. {
  868.   register int len = param ? strlen (param) : 0;
  869.   register char *end = param + len;
  870.   register char *p, *ret, c;
  871.  
  872.   if (pattern == NULL || *pattern == '\0')    /* minor optimization */
  873.     return (savestring (param));
  874.  
  875.   if (param == NULL || *param == '\0')
  876.     return (param);
  877.  
  878.   switch (op)
  879.     {
  880.       case RP_LONG_LEFT:    /* remove longest match at start */
  881.     for (p = end; p >= param; p--)
  882.       {
  883.         c = *p; *p = '\0';
  884.         if (glob_match (pattern, param, 0))
  885.           {
  886.         *p = c;
  887.         return (savestring (p));
  888.           }
  889.         *p = c;
  890.       }
  891.     break;
  892.  
  893.       case RP_SHORT_LEFT:    /* remove shortest match at start */
  894.     for (p = param; p <= end; p++)
  895.       {
  896.         c = *p; *p = '\0';
  897.         if (glob_match (pattern, param, 0))
  898.           {
  899.         *p = c;
  900.         return (savestring (p));
  901.           }
  902.         *p = c;
  903.       }
  904.     break;
  905.  
  906.       case RP_LONG_RIGHT:    /* remove longest match at end */
  907.     for (p = param; p <= end; p++)
  908.       {
  909.         if (glob_match (pattern, p, 0))
  910.           {
  911.         c = *p;
  912.         *p = '\0';
  913.         ret = savestring (param);
  914.         *p = c;
  915.         return (ret);
  916.           }
  917.       }
  918.     break;
  919.  
  920.       case RP_SHORT_RIGHT:    /* remove shortest match at end */
  921.     for (p = end; p >= param; p--)
  922.       {
  923.         if (glob_match (pattern, p, 0))
  924.           {
  925.         c = *p;
  926.         *p = '\0';
  927.         ret = savestring (param);
  928.         *p = c;
  929.         return (ret);
  930.           }
  931.       }
  932.     break;
  933.     }
  934.   return (savestring (param));    /* no match, return original string */
  935. }
  936.  
  937. /*******************************************
  938.  *                       *
  939.  *    Functions to expand WORD_DESCs       *
  940.  *                       *
  941.  *******************************************/
  942.  
  943. /* Expand WORD, performing word splitting on the result.  This does
  944.    parameter expansion, command substitution, arithmetic expansion,
  945.    word splitting, and quote removal. */
  946.  
  947. WORD_LIST *
  948. expand_word (word, quoted)
  949.      WORD_DESC *word;
  950.      int quoted;
  951. {
  952.   WORD_LIST *word_list_split (), *expand_word_internal ();
  953.   WORD_LIST *result, *tresult;
  954.  
  955.   tresult = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  956.   result = word_list_split (tresult);
  957.   dispose_words (tresult);
  958.   if (result)
  959.     dequote (result);
  960.   return (result);
  961. }
  962.  
  963. /* Expand WORD, but do not perform word splitting on the result.  This
  964.    does parameter expansion, command substitution, arithmetic expansion,
  965.    and quote removal. */
  966. WORD_LIST *
  967. expand_word_no_split (word, quoted)
  968.      WORD_DESC *word;
  969.      int quoted;
  970. {
  971.   WORD_LIST *expand_word_internal ();
  972.   WORD_LIST *result;
  973.  
  974.   result = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  975.   if (result)
  976.     dequote (result);
  977.   return (result);
  978. }
  979.  
  980. WORD_LIST *
  981. expand_word_leave_quoted (word, quoted)
  982.      WORD_DESC *word;
  983.      int quoted;
  984. {
  985.   WORD_LIST *expand_word_internal (), *result;
  986.  
  987.   result = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  988.   return (result);
  989. }
  990.  
  991. char *
  992. get_dollar_var_value (ind)
  993.      int ind;
  994. {
  995.   char *temp;
  996.  
  997.   if (ind < 10)
  998.     {
  999.       if (dollar_vars[ind])
  1000.     temp = savestring (dollar_vars[ind]);
  1001.       else
  1002.     temp = (char *)NULL;
  1003.     }
  1004.   else    /* We want something like ${11} */
  1005.     {
  1006.       WORD_LIST *p = rest_of_args;
  1007.  
  1008.       ind -= 10;
  1009.       while (p && ind--)
  1010.     p = p->next;
  1011.       if (p)
  1012.     temp = savestring (p->word->word);
  1013.       else
  1014.     temp = (char *)NULL;
  1015.     }
  1016.   return (temp);
  1017. }
  1018.  
  1019. /* Perform command substitution on STRING.  This returns a string,
  1020.    possibly quoted. */
  1021. static char *
  1022. command_substitute (string, quoted)
  1023.      char *string;
  1024.      int quoted;
  1025. {
  1026.   pid_t pid, old_pid;
  1027.   int fildes[2];
  1028.   char *istring = (char *)NULL;
  1029.   int istring_index, istring_size, c = 1;
  1030.   extern int interactive, last_command_exit_value;
  1031.  
  1032.   istring_index = istring_size = 0;
  1033.  
  1034.   /* Pipe the output of executing STRING into the current shell. */
  1035.   if (pipe (fildes) < 0)
  1036.     {
  1037.       report_error ("Can't make pipes for command substitution!");
  1038.       goto error_exit;
  1039.     }
  1040.       
  1041.   old_pid = last_made_pid;
  1042. #if defined (JOB_CONTROL)
  1043.   {
  1044.     pipeline_pgrp = shell_pgrp;
  1045.     pid = make_child (savestring ("command substitution"), 0);
  1046.  
  1047.     stop_making_children ();
  1048.     pipeline_pgrp = (pid_t)0;
  1049.   }
  1050. #else   /* JOB_CONTROL */
  1051.   pid = make_child (savestring ("command substitution"), 0);
  1052. #endif  /* JOB_CONTROL */
  1053.  
  1054.   if (pid < 0)
  1055.     {
  1056.       report_error ("Can't make a child for command substitution!");
  1057.     error_exit:
  1058.       if (istring)
  1059.     free (istring);
  1060.       return ((char *)NULL);
  1061.     }
  1062.  
  1063.   if (pid == 0)
  1064.     {
  1065. #if defined (JOB_CONTROL)
  1066.       set_job_control (0);
  1067. #endif
  1068.       if (dup2 (fildes[1], 1) < 0)
  1069.     {
  1070.       extern int errno;
  1071.       report_error ("cannot duplicate pipe as fd 1: %s\n",
  1072.             strerror (errno));
  1073.       exit (EXECUTION_FAILURE);
  1074.     }
  1075.       close (fildes[1]);
  1076.       /* If standard output is closed in the parent shell
  1077.      (such as after `exec >&-'), file descriptor 1 will be
  1078.      the lowest available file descriptor, and end up in
  1079.      fildes[0].  This can happen for stdin and stderr as well,
  1080.      but stdout is more important -- it will cause no output
  1081.      to be generated from this command. */
  1082.       if (fildes[0] > 2)
  1083.     close (fildes[0]);
  1084.       interactive = 0;
  1085.  
  1086.       exit (parse_and_execute (string, "command substitution"));
  1087.     }
  1088.   else
  1089.     {
  1090.       FILE *istream = fdopen (fildes[0], "r");
  1091.  
  1092. #if defined (JOB_CONTROL)
  1093.       close_pgrp_pipe ();
  1094. #endif
  1095.       close (fildes[1]);
  1096.  
  1097.       if (!istream)
  1098.     {
  1099.       report_error ("Can't reopen pipe to command substitution");
  1100.       goto error_exit;
  1101.     }
  1102.  
  1103.       /* Read the output of the command through the pipe. */
  1104.       while (1)
  1105.     {
  1106. #if defined (USG) || (defined (_POSIX_VERSION) && defined (Ultrix))
  1107.       c = sysv_getc (istream);
  1108. #else
  1109.       c = getc (istream);
  1110. #endif
  1111.  
  1112.       if (c == EOF)
  1113.         break;
  1114.  
  1115.       /* Add the character to ISTRING. */
  1116.       while (istring_index + 1 >= istring_size)
  1117.         istring = (char *) xrealloc
  1118.           (istring, istring_size += DEFAULT_ARRAY_SIZE);
  1119.  
  1120.       if (quoted)
  1121.         istring[istring_index++] = QUOTE_CHAR (c);
  1122.       else
  1123.         istring[istring_index++] = c;
  1124.  
  1125.       istring[istring_index] = '\0';
  1126.     }
  1127.  
  1128.       fclose (istream);
  1129.       close (fildes[0]);
  1130.  
  1131.       last_command_exit_value = wait_for (pid);
  1132.       last_made_pid = old_pid;
  1133.  
  1134. #if defined (JOB_CONTROL)
  1135.       /* If last_command_exit_value > 128, then the substituted command
  1136.      was terminated by a signal.  If that signal was SIGINT, then send
  1137.      SIGINT to ourselves.  This will break out of loops, for instance. */
  1138.       if (last_command_exit_value == (128 + SIGINT))
  1139.     kill (getpid (), SIGINT);
  1140. #endif /* JOB_CONTROL */
  1141.  
  1142.       /* If we read no output, just return now and save ourselves some
  1143.      trouble. */
  1144.       if (istring_index == 0)
  1145.     goto error_exit;
  1146.  
  1147.       /* Strip trailing newlines from the output of the command. */
  1148.       if (quoted)
  1149.     {
  1150.       while (istring_index > 0 &&
  1151.           DEQUOTE_CHAR (istring[istring_index - 1]) == '\n')
  1152.         --istring_index;
  1153.  
  1154.       istring[istring_index] = '\0';
  1155.     }
  1156.       else
  1157.     {
  1158.       strip_trailing (istring, 1);
  1159.       istring_index = strlen (istring);
  1160.     }
  1161.  
  1162.       return (istring);
  1163.     }
  1164. }
  1165.  
  1166. /* Make a word list which is the expansion of the word passed in WORD.
  1167.    This returns a WORD_LIST * if the expansion expands to something,
  1168.    else it returns NULL.  If QUOTED is non-zero, then the text of WORD is
  1169.    treated as if it was surrounded by double-quotes.  If CONTAINS_DOLLAR_AT
  1170.    is non-NULL, then it will get 1 if word contained $@ and 0 otherwise.
  1171.  
  1172.    This does not do word splitting, so the only way WORD can expand into
  1173.    a WORD_LIST of multiple elements is if it contains a quoted $@.  In that
  1174.    case, we split on ' '.
  1175.  
  1176.    This does parameter and variable expansion, command substitution, and
  1177.    arithmetic substitution. */
  1178.  
  1179. WORD_LIST *
  1180. expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
  1181.      WORD_DESC *word;
  1182.      int quoted;
  1183.      int *contains_dollar_at;
  1184.      int *expanded_something;   /* If non-null, this gets 1 if we actually expand a word */
  1185. {
  1186.   extern int last_command_exit_value;
  1187.  
  1188.   /* The thing that we finally output. */
  1189.   WORD_LIST *result = (WORD_LIST *)NULL;
  1190.  
  1191.   /* The intermediate string that we build while expanding. */
  1192.   char *istring = (char *)xmalloc (DEFAULT_ARRAY_SIZE);
  1193.  
  1194.   /* The current size of the above object. */
  1195.   int istring_size = DEFAULT_ARRAY_SIZE;
  1196.  
  1197.   /* Index into ISTRING. */
  1198.   int istring_index = 0;
  1199.  
  1200.   /* Temporary string storage. */
  1201.   char *temp = (char *)NULL;
  1202.  
  1203.   /* The text of WORD. */
  1204.   register char *string = word->word;
  1205.  
  1206.   /* The index into STRING. */
  1207.   register int sindex = 0;
  1208.  
  1209.   /* This gets 1 if we see a $@ while quoted. */
  1210.   int quoted_dollar_at = 0;
  1211.  
  1212.   register int c;        /* Current character. */
  1213.   int number;            /* Temporary number value. */
  1214.   int t_index;            /* For calls to string_extract_xxx. */
  1215.   extern int interactive;
  1216.   char *command_subst_result;    /* For calls to command_substitute (). */
  1217.  
  1218.   istring[0] = '\0';
  1219.  
  1220.   if (!string) goto final_exit;
  1221.  
  1222.   if (contains_dollar_at)
  1223.     *contains_dollar_at = 0;
  1224.  
  1225.   /* Begin the expansion. */
  1226.  
  1227.   for (;;) {
  1228.  
  1229.     c = string[sindex];
  1230.  
  1231.     switch (c) {        /* Case on toplevel character. */
  1232.  
  1233.     case '\0':
  1234.       goto finished_with_string;
  1235.  
  1236.     case '$':
  1237.  
  1238.       if (expanded_something)
  1239.     *expanded_something = 1;
  1240.  
  1241.       c = string[++sindex];
  1242.  
  1243.       /* Do simple cases first... */
  1244.  
  1245.       switch (c) {        /* Case on what follows '$'. */
  1246.  
  1247.       case '0':            /* $0 .. $9? */
  1248.       case '1':
  1249.       case '2':
  1250.       case '3':
  1251.       case '4':
  1252.       case '5':
  1253.       case '6':
  1254.       case '7':
  1255.       case '8':
  1256.       case '9':
  1257. #define SINGLE_DIGIT_COMPATIBILITY /* I'm beginning to hate Bourne. */
  1258. #ifdef SINGLE_DIGIT_COMPATIBILITY
  1259.     if (dollar_vars[digit_value (c)])
  1260.       temp = savestring (dollar_vars[digit_value (c)]);
  1261.     else
  1262.       temp = (char *)NULL;
  1263. #else /* We read the whole number, not just the first digit. */
  1264. #endif
  1265.     goto dollar_add_string;
  1266.  
  1267.       case '$':            /* $$ -- pid of the invoking shell. */
  1268.     {
  1269.       extern int dollar_dollar_pid;
  1270.       number = dollar_dollar_pid;
  1271.     }
  1272. add_number:
  1273.     temp = itos (number);
  1274. dollar_add_string:
  1275.     if (string[sindex]) sindex++;
  1276.  
  1277.     /* Add TEMP to ISTRING. */
  1278. add_string:
  1279.     istring = sub_append_string (temp, istring,
  1280.                      &istring_index, &istring_size);
  1281.     break;
  1282.  
  1283.       case '#':            /* $# -- number of positional parameters. */
  1284.     {
  1285.       WORD_LIST *list = list_rest_of_args ();
  1286.       number = list_length (list);
  1287.       dispose_words (list);
  1288.       goto add_number;
  1289.     }
  1290.     /* break; */
  1291.  
  1292.       case '?':            /* $? -- return value of the last synchronous command. */
  1293.     number = last_command_exit_value;
  1294.     goto add_number;
  1295.     /* break; */
  1296.  
  1297.       case '-':            /* $- -- flags supplied to the shell on
  1298.                    invocation or by the `set' builtin. */
  1299.     temp = (char *)which_set_flags ();
  1300.     goto dollar_add_string;
  1301.     /* break; */
  1302.  
  1303.       case '!':            /* $! -- Pid of the last asynchronous command. */
  1304.     {
  1305.       number = (int)last_asynchronous_pid;
  1306.       goto add_number;
  1307.     }
  1308.     /* break; */
  1309.  
  1310.     /* The only difference between this and $@ is when the arg is
  1311.        quoted. */
  1312.       case '*':            /* `$*' */
  1313.     temp = string_rest_of_args (quoted);
  1314.  
  1315.     /* In the case of a quoted string, quote the entire arg-list.
  1316.        "$1 $2 $3". */
  1317.     if (quoted && temp)
  1318.       quote_string (temp);
  1319.     goto dollar_add_string;
  1320.     /* break; */
  1321.  
  1322.     /* When we have "$@" what we want is "$1" "$2" "$3" ... This
  1323.        means that we have to turn quoting off after we split into
  1324.        the individually quoted arguments so that the final split
  1325.        on the first character of $IFS is still done.  */
  1326.       case '@':            /* `$@' */
  1327.     {
  1328.       WORD_LIST *tlist = list_rest_of_args ();
  1329.       if (quoted && tlist)
  1330.         quote_list (tlist);
  1331.  
  1332.       /* We want to flag the fact that we saw this.  We can't turn off
  1333.          quoting entirely, because other characters in the string might
  1334.          need it (consider "\"$@\""), but we need some way to signal
  1335.          that the final split on the first character of $IFS should be
  1336.          done, even though QUOTED is 1. */
  1337.       if (quoted)
  1338.         quoted_dollar_at = 1;
  1339.       if (contains_dollar_at)
  1340.         *contains_dollar_at = 1;
  1341.       temp = string_list (tlist);
  1342.       goto dollar_add_string;
  1343.       /* break; */
  1344.     }
  1345.  
  1346.       case '{':            /* ${[#]name[[:]#[#]%[%]-=?+[word]]} */
  1347.     {
  1348.       int check_nullness = 0;
  1349.       int var_is_set = 0;
  1350.       int var_is_null = 0;
  1351.       int var_is_special = 0;
  1352.       char *name, *value, *string_extract ();
  1353.  
  1354.       sindex++;
  1355.       t_index = sindex;
  1356.       name = string_extract (string, &t_index, "#%:-=?+}");
  1357.  
  1358.       /* If the name really consists of a special variable, then
  1359.          make sure that we have the entire name. */
  1360.       if (sindex == t_index &&
  1361.           (string[sindex] == '-' ||
  1362.            string[sindex] == '?' ||
  1363.            string[sindex] == '#'))
  1364.         {
  1365.           char *tt;
  1366.           t_index++;
  1367.           free (name);
  1368.           tt = (string_extract (string, &t_index, "#%:-=?+}"));
  1369.           name = (char *)xmalloc (2 + (strlen (tt)));
  1370.           *name = string[sindex];
  1371.           strcpy (name + 1, tt);
  1372.           free (tt);
  1373.         }
  1374.       sindex = t_index;
  1375.  
  1376.       /* Find out what character ended the variable name.  Then
  1377.          do the appropriate thing. */
  1378.  
  1379.       if (c = string[sindex])
  1380.         sindex++;
  1381.  
  1382.       if (c == ':')
  1383.         {
  1384.           check_nullness++;
  1385.           if (c = string[sindex])
  1386.         sindex++;
  1387.         }
  1388.  
  1389.       /* Determine the value of this variable. */
  1390.       if (strlen (name) == 1 && (digit(*name) || member(*name, "#-?$!@*")))
  1391.         var_is_special++;
  1392.  
  1393.       /* Check for special expansion things. */
  1394.       if (*name == '#')
  1395.         {
  1396.           if (name[1] != '*' && name[1] != '@')
  1397.         {
  1398.           char *tt;
  1399.  
  1400.           number = 0;
  1401.           if (digit (name[1]))        /* ${#1} */
  1402.             {
  1403.               tt = get_dollar_var_value (atoi (&name[1]));
  1404.               if (tt)
  1405.             {
  1406.               number = strlen (tt);
  1407.               free (tt);
  1408.             }
  1409.             }
  1410.           else
  1411.             {
  1412.               tt = get_string_value (&name[1]);
  1413.               if (tt)
  1414.             number = strlen (tt);
  1415.             }
  1416.         }
  1417.           else
  1418.         {
  1419.           char *t = string_rest_of_args (1);
  1420.           number = strlen (t);
  1421.           free (t);
  1422.         }
  1423.           goto add_number;
  1424.         }
  1425.  
  1426.       if (digit (*name))
  1427.         {
  1428.           int ind = atoi (name);
  1429.  
  1430.           var_is_special++;
  1431.           temp = get_dollar_var_value (ind);
  1432.           if (temp)
  1433.         var_is_set++;
  1434.         }
  1435.       else if (var_is_special)
  1436.         {
  1437.           char *tt = (char *)alloca (2 + strlen (name));
  1438.           WORD_LIST *l;
  1439.           tt[0] = '$'; tt[1] = '\0';
  1440.           strcat (tt, name);
  1441.           l = expand_string_leave_quoted (tt, quoted);
  1442.  
  1443.           /* ${@} is the same as $@ */
  1444.           if (name[0] == '@' && name[1] == '\0')
  1445.         {
  1446.           if (quoted)
  1447.             quoted_dollar_at = 1;
  1448.           if (contains_dollar_at)
  1449.             *contains_dollar_at = 1;
  1450.         }
  1451.  
  1452.           temp = string_list (l);
  1453.           dispose_words (l);
  1454.  
  1455.           if (temp)
  1456.         var_is_set++;
  1457.         }
  1458.       else
  1459.         {
  1460.           char *get_string_value ();
  1461.           SHELL_VAR *f = find_variable (name);
  1462.  
  1463.           if (f && !invisible_p (f) &&
  1464.           ((temp = get_string_value (name)) != (char *)NULL))
  1465.         {
  1466.           temp = savestring (temp);
  1467.           var_is_set++;
  1468.         }
  1469.           else
  1470.         temp = (char *)NULL;
  1471.         }
  1472.  
  1473.       if (!var_is_set || !temp || !*temp)
  1474.         var_is_null++;
  1475.  
  1476.       if (!check_nullness)
  1477.         var_is_null = 0;
  1478.  
  1479.       /* Get the rest of the stuff inside the braces. */
  1480.       if (c && c != '}')
  1481.         {
  1482.           /* Scan forward searching for last `{'.  This is a hack,
  1483.          it will always be a hack, and it always has been a hack. */
  1484.           {
  1485.         int braces_found = 0;
  1486.  
  1487.         for (t_index = sindex; string[t_index]; t_index++)
  1488.           {
  1489.             if (string[t_index] == '{')
  1490.               braces_found++;
  1491.             else
  1492.               if (string[t_index] == '}')
  1493.             if (!braces_found)
  1494.               break;
  1495.             else
  1496.               braces_found--;
  1497.           }
  1498.  
  1499.         value = (char *)xmalloc (1 + (t_index - sindex));
  1500.         strncpy (value, &string[sindex], t_index - sindex);
  1501.         value[t_index - sindex] = '\0';
  1502.         sindex = t_index;
  1503.           }
  1504.  
  1505.           if (string[sindex] == '}') sindex++;
  1506.           else goto bad_substitution;
  1507.  
  1508.         }
  1509.       else
  1510.         {
  1511.           value = (char *)NULL;
  1512.         }
  1513.  
  1514.       /* Do the right thing based on which character ended the variable
  1515.          name. */
  1516.       switch (c)
  1517.         {
  1518.         case '\0':
  1519.         bad_substitution:
  1520.           report_error ("%s: bad substitution", name ? name : "??");
  1521.           longjmp (top_level, DISCARD);
  1522.  
  1523.         case '}':
  1524.           break;
  1525.  
  1526.         case '#':    /* ${param#[#]pattern} */
  1527.           if (!value || !*value || !temp || !*temp)
  1528.         break;
  1529.  
  1530.           if (*value == '#')
  1531.         {
  1532.           WORD_LIST *l = expand_string (++value, 0);
  1533.           char *pattern = (char *)string_list (l);
  1534.           char *t = temp;
  1535.           dispose_words (l);
  1536.           temp = remove_pattern (t, pattern, RP_LONG_LEFT);
  1537.           free (t);
  1538.           free (pattern);
  1539.         }
  1540.           else
  1541.         {
  1542.           WORD_LIST *l = expand_string (value, 0);
  1543.           char *pattern = string_list (l);
  1544.           char *t = temp;
  1545.           dispose_words (l);
  1546.           temp = remove_pattern (t, pattern, RP_SHORT_LEFT);
  1547.           free (t);
  1548.           free (pattern);
  1549.         }
  1550.           break;
  1551.  
  1552.         case '%':    /* ${param%[%]pattern} */
  1553.           if (!value || !*value || !temp || !*temp)
  1554.         break;
  1555.  
  1556.           if (*value == '%')
  1557.         {
  1558.           WORD_LIST *l = expand_string (++value, 0);
  1559.           char *pattern = string_list (l);
  1560.           char *t = temp;
  1561.           dispose_words (l);
  1562.           temp = remove_pattern (t, pattern, RP_LONG_RIGHT);
  1563.           free (t);
  1564.           free (pattern);
  1565.         }
  1566.           else
  1567.         {
  1568.           WORD_LIST *l = expand_string (value, 0);
  1569.           char *pattern = string_list (l);
  1570.           char *t = temp;
  1571.           dispose_words (l);
  1572.           temp = remove_pattern (t, pattern, RP_SHORT_RIGHT);
  1573.           free (t);
  1574.           free (pattern);
  1575.         }
  1576.           break;
  1577.  
  1578.         case '-':
  1579.           if (var_is_set && !var_is_null)
  1580.         {
  1581.           /* Do nothing.  Just use the value in temp. */
  1582.         }
  1583.           else
  1584.         {
  1585.           WORD_LIST *l = expand_string_leave_quoted (value, quoted);
  1586.           if (temp)
  1587.             free (temp);
  1588.           temp = (char *)string_list (l);
  1589.           dispose_words (l);
  1590.           free (value);
  1591.         }
  1592.           break;
  1593.  
  1594.         case '=':
  1595.           if (var_is_set && !var_is_null)
  1596.         {
  1597.           /* Do nothing.  The value of temp is desired. */
  1598.         }
  1599.           else
  1600.         {
  1601.           if (var_is_special)
  1602.             {
  1603.               report_error ("$%s: cannot assign in this way", name);
  1604.               if (temp)
  1605.             free (temp);
  1606.               temp = (char *)NULL;
  1607.             }
  1608.           else
  1609.             {
  1610.               WORD_LIST *l = expand_string_leave_quoted (value, quoted);
  1611.               char *t;
  1612.               if (temp)
  1613.             free (temp);
  1614.               temp = (char *)string_list (l);
  1615.               dispose_words (l);
  1616.               t = savestring (temp);    /* XXX was just bind_variable (name, temp) */
  1617.               dequote_string (t);
  1618.               bind_variable (name, t);
  1619.               free (t);
  1620.             }
  1621.         }
  1622.           break;
  1623.  
  1624.         case '?':
  1625.           if (var_is_set && !var_is_null)
  1626.         {
  1627.           /* Do nothing.  The value in temp is desired. */
  1628.         }
  1629.           else
  1630.         {
  1631.           /* The spec says to "print `word' [the right hand
  1632.              side], and exit from the shell", but I think that
  1633.              is brain-damaged beyond all belief.  I also haven't
  1634.              found another shell that does that yet.  I don't
  1635.              think that I ever will find one.  The spec goes on
  1636.              to then say "If `word' is omitted, the message
  1637.              ``parameter null or not set'' is printed", but that
  1638.              is so stupid it is clearly to be ignored.  I just
  1639.              print whatever was found on the right-hand of the
  1640.              statement.  If nothing is found on the right hand
  1641.              side, I am told that I must print a default error
  1642.              message and exit from the shell.  Remember, this
  1643.              isn't my idea.  */
  1644.  
  1645.           if (value && *value)
  1646.             {
  1647.               WORD_LIST *l = expand_string (value, 0);
  1648.               char *temp1 =  string_list (l);
  1649.               fprintf (stderr, "%s: %s\n", name, temp1 ? temp1 : value);
  1650.               if (temp1)
  1651.             free (temp1);
  1652.               dispose_words (l);
  1653.             }
  1654.           else
  1655.             {
  1656.               if (var_is_special)
  1657.             report_error ("%s: Too few arguments", dollar_vars[0]);
  1658.               else
  1659.             report_error ("%s: parameter not set", name);
  1660.             }
  1661.  
  1662.           if (temp)
  1663.             free (temp);
  1664.  
  1665.           if (!interactive)
  1666.             longjmp (top_level, FORCE_EOF);
  1667.           else
  1668.             longjmp (top_level, DISCARD);
  1669.         }
  1670.           break;
  1671.  
  1672.         case '+':
  1673.           /* We don't want the value of the named variable for anything. */
  1674.           if (temp)
  1675.         free (temp);
  1676.           temp = (char *)NULL;
  1677.  
  1678.           if (var_is_set && !var_is_null)
  1679.         {
  1680.           /* Use the right-hand side.  Pretty weird. */
  1681.           if (value)
  1682.             {
  1683.               WORD_LIST *l = expand_string_leave_quoted (value, quoted);
  1684.               temp = (char *)string_list (l);
  1685.               dispose_words (l);
  1686.             }
  1687.         }
  1688.           break;
  1689.         }            /* end case on closing character. */
  1690.       free (name);
  1691.       goto add_string;
  1692.     }            /* end case '{' */
  1693.       /* break; */
  1694.  
  1695.       case '(':            /* Do command substitution. */
  1696.     /* We have to extract the contents of this paren substitution. */
  1697.     {
  1698.       char *extract_command_subst ();
  1699.       int old_index = ++sindex;
  1700.  
  1701.       temp = extract_command_subst (string, &old_index);
  1702.       sindex = old_index;
  1703.  
  1704.       goto handle_command_substitution;
  1705.       break;
  1706.     }
  1707.  
  1708.       case '[':            /* Do arithmetic substitution. */
  1709.     /* We have to extract the contents of this arithmetic substitution. */
  1710.     {
  1711.       char *extract_arithmetic_subst (), *t;
  1712.       int old_index = ++sindex;
  1713.       WORD_LIST *l;
  1714.       extern long evalexp ();
  1715.       extern char *this_command_name;
  1716.  
  1717.       temp = extract_arithmetic_subst (string, &old_index);
  1718.       sindex = old_index;
  1719.  
  1720.       l = expand_string (temp, 1);    /* do initial variable expansion */
  1721.       t = string_list (l);
  1722.       dispose_words (l);
  1723.       this_command_name = (char *)NULL; /* No error messages. */
  1724.       number = (int)evalexp (t);
  1725.       free (t);
  1726.  
  1727.       goto add_number;
  1728.     }
  1729.  
  1730.       default:
  1731.     {
  1732.       /* Find the variable in VARIABLE_LIST. */
  1733.       int old_index = sindex;
  1734.       char *name;
  1735.       SHELL_VAR *var;
  1736.  
  1737.       temp = (char *)NULL;
  1738.  
  1739.       for (;
  1740.            (c = string[sindex]) && (isletter (c) || digit (c) || c == '_');
  1741.            sindex++);
  1742.       name = (char *)substring (string, old_index, sindex);
  1743.  
  1744.       /* If this isn't a variable name, then just output the `$'. */
  1745.       if (!name || !*name) {
  1746.         free (name);
  1747.         temp = savestring ("$");
  1748.         if (expanded_something)
  1749.           *expanded_something = 0;
  1750.         goto add_string;
  1751.       }
  1752.  
  1753.       /* If the variable exists, return its value cell. */
  1754.       var = find_variable (name);
  1755.  
  1756.       if (var && value_cell (var))
  1757.         {
  1758.           temp = savestring (value_cell (var));
  1759.           free (name);
  1760.           goto add_string;
  1761.         }
  1762.       else
  1763.         temp = (char *)NULL;
  1764.  
  1765.       if (var && !temp && function_cell (var))
  1766.         {
  1767.           report_error ("%s: cannot substitute function", name);
  1768.         }
  1769.       else
  1770.         {
  1771.           if (unbound_vars_is_error)
  1772.         {
  1773.           report_error ("%s: unbound variable", name);
  1774.         }
  1775.           else
  1776.         goto add_string;
  1777.       }
  1778.       free (name);
  1779.       longjmp (top_level, DISCARD);
  1780.     }
  1781.       }
  1782.       break;            /* End case '$': */
  1783.  
  1784.     case '`':            /* Backquoted command substitution. */
  1785.       {
  1786.     sindex++;
  1787.  
  1788.     if (expanded_something)
  1789.       *expanded_something = 1;
  1790.  
  1791.     t_index = sindex;
  1792.     temp = string_extract (string, &t_index, "`");
  1793.     sindex = t_index;
  1794.     de_backslash (temp);
  1795.  
  1796.       handle_command_substitution:
  1797.     command_subst_result = command_substitute (temp, quoted);
  1798.  
  1799.     if (temp)
  1800.       free (temp);
  1801.  
  1802.     temp = command_subst_result;
  1803.  
  1804.     if (string[sindex])
  1805.       sindex++;
  1806.  
  1807.     goto add_string;
  1808.     break;
  1809.       }
  1810.  
  1811.     case '\\':
  1812.       if (string[sindex + 1] == '\n')
  1813.     {
  1814.       sindex += 2;
  1815.       continue;
  1816.     }
  1817.       else
  1818.     {
  1819.       char *slashify_chars = "";
  1820.  
  1821.       c = string[++sindex];
  1822.  
  1823.       if (quoted == Q_HERE_DOCUMENT)
  1824.         slashify_chars = slashify_in_here_document;
  1825.       else if (quoted == Q_DOUBLE_QUOTES)
  1826.         slashify_chars = slashify_in_quotes;
  1827.  
  1828.       if (quoted && !member (c, slashify_chars))
  1829.         {
  1830.           temp = (char *)xmalloc (3);
  1831.           temp[0] = '\\'; temp[1] = c; temp[2] = '\0';
  1832.           if (c)
  1833.         sindex++;
  1834.           goto add_string;
  1835.         }
  1836.       else
  1837.         {
  1838.           /* This character is quoted, so add it in quoted mode. */
  1839.           c = QUOTE_CHAR (c);
  1840.           goto add_character;
  1841.         }
  1842.     }
  1843.  
  1844.     case '"':
  1845.       if (quoted)
  1846.     goto add_character;
  1847.       sindex++;
  1848.       {
  1849.     WORD_LIST *tresult = (WORD_LIST *)NULL;
  1850.  
  1851.     t_index = sindex;
  1852.     temp = string_extract_double_quoted (string, &t_index);
  1853.     sindex = t_index;
  1854.  
  1855.     if (string[sindex])
  1856.       sindex++;
  1857.  
  1858.     if (temp && *temp)
  1859.       {
  1860.         int dollar_at_flag;
  1861.         WORD_DESC *temp_word = make_word (temp);
  1862.  
  1863.         free (temp);
  1864.  
  1865.         tresult = expand_word_internal
  1866.           (temp_word, Q_DOUBLE_QUOTES, &dollar_at_flag, (int *)NULL);
  1867.  
  1868.         dispose_word (temp_word);
  1869.  
  1870.         if (!tresult && dollar_at_flag)
  1871.           break;
  1872.         /* If we get "$@", we know we have expanded something, so we
  1873.            need to remember it for the final split on $IFS.  This is
  1874.            a special case; it's the only case where a quoted string
  1875.            can expand into more than one word.  It's going to come back
  1876.            from the above call to expand_word_internal as a list with
  1877.            a single word, in which all characters are quoted and
  1878.            separated by blanks.  What we want to do is to turn it back
  1879.            into a list for the next piece of code. */
  1880.         dequote (tresult);
  1881.         if (dollar_at_flag)
  1882.           quoted_dollar_at++;
  1883.         if (expanded_something)
  1884.           *expanded_something = 1;
  1885.       }
  1886.     else
  1887.       {
  1888.         /* What we have is "".  This is a minor optimization. */
  1889.         free (temp);
  1890.         tresult = (WORD_LIST *)NULL;
  1891.       }
  1892.  
  1893.     /* the code above *might* return a list (consider the case of "$@",
  1894.        where it returns "$1", "$2", and so on).  We can't throw away
  1895.        the rest of the list, and we have to make sure each word gets
  1896.        added as quoted.  We test on tresult->next:  if it is non-NULL,
  1897.        we  quote the whole list, save it to a string with string_list,
  1898.        and add that string. We don't need to quote the results of this
  1899.        (and it would be wrong, since that would quote the separators
  1900.        as well), so we go directly to add_string. */
  1901.  
  1902.     if (tresult)
  1903.       {
  1904.         if (tresult->next)
  1905.           {
  1906.         quote_list (tresult);
  1907.         temp = string_list (tresult);
  1908.         dispose_words (tresult);
  1909.         goto add_string;
  1910.           }
  1911.         else
  1912.           {
  1913.         temp = savestring (tresult->word->word);
  1914.         dispose_words (tresult);
  1915.           }
  1916.       }
  1917.     else
  1918.       temp = (char *)NULL;
  1919.  
  1920.       add_quoted_string:
  1921.  
  1922.     if (temp)
  1923.       quote_string (temp);
  1924.     else
  1925.       {
  1926.       add_null_arg:
  1927.         temp = savestring (" ");
  1928.         temp[0] = (unsigned char)QUOTE_CHAR ('\0');
  1929.       }
  1930.     goto add_string;
  1931.       }
  1932.       /* break; */
  1933.  
  1934.     case '\'':
  1935.       {
  1936.     if (!quoted)
  1937.       {
  1938.         sindex++;
  1939.  
  1940.         t_index = sindex;
  1941.         temp = string_extract_verbatim (string, &t_index, "'");
  1942. #if 0
  1943.         if (history_expansion)
  1944.           unquote_bang (temp);
  1945. #endif
  1946.         sindex = t_index;
  1947.  
  1948.         if (string[sindex]) sindex++;
  1949.  
  1950.         if (!*temp)
  1951.           {
  1952.         free (temp);
  1953.         temp = (char *)NULL;
  1954.           }
  1955.  
  1956.         goto add_quoted_string;
  1957.       }
  1958.     else
  1959.       goto add_character;
  1960.  
  1961.     break;
  1962.       }
  1963.  
  1964.     default:
  1965.  
  1966.       /* This is the fix for " $@ " */
  1967.       if (quoted)
  1968.     c = QUOTE_CHAR (c);
  1969.  
  1970. add_character:
  1971.       while (istring_index + 1 >= istring_size)
  1972.     istring = (char *)
  1973.       xrealloc (istring, istring_size += DEFAULT_ARRAY_SIZE);
  1974.       istring[istring_index++] = c;
  1975.       istring[istring_index] = '\0';
  1976.  
  1977. next_character:
  1978.       sindex++;
  1979.     }
  1980.   }
  1981.  
  1982. finished_with_string:
  1983. final_exit:
  1984.   /* OK, we're ready to return.  If we have a quoted string, and
  1985.      quoted_dollar_at is not set, we do no splitting at all; otherwise
  1986.      we split on ' '.  The routines that call this will handle what to
  1987.      do if nothing has been expanded. */
  1988.   if (istring)
  1989.     {
  1990.       WORD_LIST *temp_list;
  1991.  
  1992.       if (quoted_dollar_at)
  1993.     temp_list = list_string (istring, " ", quoted);
  1994.       else if (*istring)
  1995.     {
  1996.       temp_list = make_word_list (make_word (istring), (WORD_LIST *)NULL);
  1997.       temp_list->word->quoted = quoted;
  1998.     }
  1999.       else
  2000.     temp_list = (WORD_LIST *)NULL;
  2001.       free (istring);
  2002.       result = (WORD_LIST *)list_append (reverse_list (result), temp_list);
  2003.     }
  2004.   else
  2005.     result = (WORD_LIST *)NULL;
  2006.  
  2007.   return (result);
  2008. }
  2009.  
  2010. /*******************************************
  2011.  *                       *
  2012.  *    Functions to perform word splitting  *
  2013.  *                       *
  2014.  *******************************************/
  2015.  
  2016. /* This splits a single word into a WORD LIST on $IFS, but only if the word
  2017.    is not quoted.  list_string () performs quote removal for us, even if we
  2018.    don't do any splitting. */
  2019. WORD_LIST *
  2020. word_split (w)
  2021.      WORD_DESC *w;
  2022. {
  2023.   WORD_LIST *result;
  2024.  
  2025.   if (w)
  2026.     {
  2027.       SHELL_VAR *ifs = find_variable ("IFS");
  2028.       char *ifs_chars;
  2029.  
  2030.       /* If IFS is unset, it defaults to " \t\n". */
  2031.       if (ifs)
  2032.     ifs_chars = value_cell (ifs);
  2033.       else
  2034.     ifs_chars = " \t\n";
  2035.  
  2036.       if (w->quoted || !ifs_chars)
  2037.     ifs_chars = "";
  2038.  
  2039.       result = list_string (w->word, ifs_chars, w->quoted);
  2040.     }
  2041.   else
  2042.     result = (WORD_LIST *)NULL;
  2043.   return (result);
  2044. }
  2045.  
  2046. /* Perform word splitting on LIST and return the RESULT.  It is possible
  2047.    to return (WORD_LIST *)NULL. */
  2048. WORD_LIST *
  2049. word_list_split (list)
  2050.      WORD_LIST *list;
  2051. {
  2052.   WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult;
  2053.  
  2054.   t = list;
  2055.   while (t)
  2056.     {
  2057.       tresult = word_split (t->word);
  2058.       result = (WORD_LIST *) list_append (result, tresult);
  2059.       t = t->next;
  2060.     }
  2061.   return (result);
  2062. }
  2063.  
  2064. /**************************************************
  2065.  *                           *
  2066.  *    Functions to expand an entire WORD_LIST      *
  2067.  *                          *
  2068.  **************************************************/
  2069.  
  2070. /* Do all of the assignments in LIST up to a word which isn't an
  2071.    assignment. */
  2072. WORD_LIST *
  2073. get_rid_of_variable_assignments (list)
  2074.      WORD_LIST *list;
  2075. {
  2076.   WORD_LIST *orig = list;
  2077.  
  2078.   while (list)
  2079.     if (!list->word->assignment)
  2080.       {
  2081.     WORD_LIST *new_list = copy_word_list (list);
  2082.     dispose_words (orig);
  2083.     return (new_list);
  2084.       }
  2085.     else
  2086.       {
  2087.     do_assignment (list->word->word);
  2088.     list = list->next;
  2089.       }
  2090.   dispose_words (orig);
  2091.   return ((WORD_LIST *)NULL);
  2092. }
  2093.  
  2094. /* Check and handle the case where there are some variable assignments
  2095.    in LIST which go into the environment for this command. */
  2096. WORD_LIST *
  2097. get_rid_of_environment_assignments (list)
  2098.      WORD_LIST *list;
  2099. {
  2100.   register WORD_LIST *tlist = list;
  2101.   register WORD_LIST *new_list;
  2102.  
  2103.   while (tlist)
  2104.     {
  2105.       if (!tlist->word->assignment) goto make_assignments;
  2106.       tlist = tlist->next;
  2107.     }
  2108.   /* Since all of the assignments are variable assignments. */
  2109.   return (list);
  2110.  
  2111. make_assignments:
  2112.   tlist = list;
  2113.   while (tlist)
  2114.     {
  2115.       if (tlist->word->assignment)
  2116.     assign_in_env (tlist->word->word);
  2117.       else
  2118.     {
  2119.       if (!place_keywords_in_env)
  2120.         {
  2121.           new_list = copy_word_list (tlist);
  2122.           dispose_words (list);
  2123.           return (new_list);
  2124.         }
  2125.     }
  2126.       tlist = tlist->next;
  2127.     }
  2128.  
  2129.   /* We got all of the keywords assigned.  Now return the remainder
  2130.      of the words. */
  2131.   {
  2132.     register WORD_LIST *new_list = (WORD_LIST *)NULL;
  2133.  
  2134.     tlist = list;
  2135.  
  2136.     /* Skip the ones at the start. */
  2137.     while (tlist && tlist->word->assignment)
  2138.       tlist = tlist->next;
  2139.  
  2140.     /* If we placed all the keywords in the list into the environment,
  2141.        then remove them from the output list. */
  2142.     if (place_keywords_in_env)
  2143.       {
  2144.     while (tlist)
  2145.       {
  2146.         if (!tlist->word->assignment)
  2147.           new_list = make_word_list (copy_word (tlist->word), new_list);
  2148.         tlist = tlist->next;
  2149.       }
  2150.     new_list = (WORD_LIST *)reverse_list (new_list);
  2151.       }
  2152.     else
  2153.       {
  2154.     /* Just copy the list. */
  2155.     new_list = copy_word_list (tlist);
  2156.       }
  2157.     dispose_words (list);
  2158.     return (new_list);
  2159.   }
  2160. }
  2161.  
  2162. /* Take the list of words in LIST and do the various substitutions.  Return
  2163.    a new list of words which is the expanded list, and without things like
  2164.    variable assignments. */
  2165. WORD_LIST *
  2166. expand_words (list)
  2167.      WORD_LIST *list;
  2168. {
  2169.   WORD_LIST *expand_words_1 ();
  2170.   return (expand_words_1 (list, 1));
  2171. }
  2172.  
  2173. /* Same as expand_words (), but doesn't hack variable or environment
  2174.    variables. */
  2175. WORD_LIST *
  2176. expand_words_no_vars (list)
  2177.      WORD_LIST *list;
  2178. {
  2179.   WORD_LIST *expand_words_1 ();
  2180.   return (expand_words_1 (list, 0));
  2181. }
  2182.  
  2183. /* Non-zero means to allow unmatched globbed filenames to expand to
  2184.    a null file. */
  2185. static int allow_null_glob_expansion = 0;
  2186.  
  2187. /* The workhorse for expand_words () and expand_words_no_var ().
  2188.    First arg is LIST, a WORD_LIST of words.
  2189.    Second arg DO_VARS is non-zero if you want to do environment and
  2190.    variable assignments, else zero.
  2191.  
  2192.    This does all of the subsitutions: brace expansion, tilde expansion,
  2193.    parameter expansion, command substitution, arithmetic expansion,
  2194.    word splitting, and pathname expansion. */
  2195.  
  2196. WORD_LIST *
  2197. expand_words_1 (list, do_vars)
  2198.      WORD_LIST *list;
  2199.      int do_vars;
  2200. {
  2201.   register WORD_LIST *tlist, *new_list = (WORD_LIST *)NULL;
  2202.   WORD_LIST *orig_list;
  2203.   extern int no_brace_expansion;
  2204.  
  2205.   tlist = (WORD_LIST *)copy_word_list (list);
  2206.  
  2207.   if (do_vars)
  2208.     {
  2209.       /* Handle the case where the arguments are assignments for
  2210.      the environment of this command. */
  2211.       tlist = get_rid_of_environment_assignments (tlist);
  2212.  
  2213.       /* Handle the case where the arguments are all variable assignments. */
  2214.       tlist = get_rid_of_variable_assignments (tlist);
  2215.     }
  2216.  
  2217.   /* Begin expanding the words that remain.  The expansions take place on
  2218.      things that aren't really variable assignments. */
  2219.  
  2220.   if (!tlist)
  2221.     return ((WORD_LIST *)NULL);
  2222.  
  2223.   /* Do brace expansion on this word if there are any brace characters
  2224.      in the string. */
  2225.   if (!no_brace_expansion)
  2226.     {
  2227.       extern char **brace_expand ();
  2228.       register char **expansions;
  2229.       WORD_LIST *braces = (WORD_LIST *)NULL;
  2230.       int eindex;
  2231.  
  2232.       orig_list = tlist;
  2233.  
  2234.       while (tlist)
  2235.     {
  2236.       /* Only do brace expansion if the word has a brace character.  If
  2237.          not, just copy the word list element, add it to braces, and
  2238.          continue.  In the common case, at least when running shell
  2239.          scripts, this will degenerate to a bunch of calls to `index',
  2240.          and then what is basically the body of copy_word_list. */
  2241.       if (index ((tlist->word->word), '{') != (int)NULL)
  2242.         {
  2243.           expansions = brace_expand (tlist->word->word);
  2244.  
  2245.           for (eindex = 0; expansions[eindex]; eindex++)
  2246.         {
  2247.           braces = make_word_list (make_word (expansions[eindex]),
  2248.                          braces);
  2249.           free (expansions[eindex]);
  2250.         }
  2251.           free (expansions);
  2252.         }
  2253.       else
  2254.         {
  2255.           WORD_LIST *new = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
  2256.           new->word = copy_word (tlist->word);
  2257.           new->next = braces;
  2258.           braces = new;
  2259.         }
  2260.  
  2261.       tlist = tlist->next;
  2262.     }
  2263.       dispose_words (orig_list);
  2264.       tlist = (WORD_LIST *)reverse_list (braces);
  2265.     }
  2266.  
  2267.   orig_list = tlist;
  2268.  
  2269.   /* We do tilde expansion all the time.  This is what 1003.2 says. */
  2270.   while (tlist)
  2271.     {
  2272.       WORD_LIST *expanded;
  2273.       WORD_LIST *t;
  2274.       int expanded_something = 0;
  2275.  
  2276.       if (!tlist->word->quoted && (*(tlist->word->word) == '~'))
  2277.     {
  2278.       char *tilde_expand (), *tt = tlist->word->word;
  2279.       tlist->word->word = tilde_expand (tlist->word->word);
  2280.       free (tt);
  2281.     }
  2282.  
  2283.       expanded = expand_word_internal (tlist->word, 0, (int *)NULL, &expanded_something);
  2284.  
  2285.       if (expanded_something)
  2286.     t = word_list_split (expanded);
  2287.       else
  2288.     t = copy_word_list (expanded);    /* no expansion, no split */
  2289.  
  2290.       new_list =
  2291.     (WORD_LIST *)list_append (reverse_list (t), new_list);
  2292.  
  2293.       dispose_words (expanded);
  2294.  
  2295.       tlist = tlist->next;
  2296.     }
  2297.  
  2298.   new_list = (WORD_LIST *)reverse_list (new_list);
  2299.  
  2300.   dispose_words (orig_list);
  2301.  
  2302.   /* Okay, we're almost done.  Now let's just do some filename
  2303.      globbing. */
  2304.   {
  2305.     char **shell_glob_filename (), **temp_list = (char **)NULL;
  2306.     register int list_index;
  2307.     WORD_LIST *glob_list;
  2308.  
  2309.     orig_list = (WORD_LIST *)NULL;
  2310.     tlist = new_list;
  2311.  
  2312.     if (!disallow_filename_globbing)
  2313.       {
  2314.     while (tlist)
  2315.       {
  2316.         /* If the word isn't quoted, then glob it. */
  2317.         if (!tlist->word->quoted && glob_pattern_p (tlist->word->word))
  2318.           {
  2319.         temp_list = shell_glob_filename (tlist->word->word);
  2320.  
  2321.         /* Fix the hi-bits. (This is how we quoted
  2322.            special characters.) */
  2323.         {
  2324.           register char *t = tlist->word->word;
  2325.           dequote_string (t);
  2326.         }
  2327.  
  2328.         /* Handle error cases.
  2329.            I don't think we should report errors like "No such file
  2330.            or directory".  However, I would like to report errors
  2331.            like "Read failed". */
  2332.  
  2333.         if (temp_list == (char **)-1)
  2334.           {
  2335.             /* file_error (tlist->word->word); */
  2336.             /* A small memory leak, I think */
  2337.             temp_list = (char **) xmalloc (sizeof (char *));
  2338.             temp_list[0] = '\0';
  2339.           }
  2340.  
  2341.         if (!temp_list) abort ();
  2342.  
  2343.         /* Sort the returned names.  Maybe this should be done in
  2344.            glob_filename (). */
  2345.         {
  2346.           int qsort_string_compare ();
  2347.           qsort (temp_list, array_len (temp_list),
  2348.              sizeof (char *), qsort_string_compare);
  2349.         }
  2350.  
  2351.         /* Make the array into a word list. */
  2352.         glob_list = (WORD_LIST *)NULL;
  2353.         for (list_index = 0; temp_list[list_index]; list_index++)
  2354.           glob_list =
  2355.             make_word_list (make_word (temp_list[list_index]), glob_list);
  2356.  
  2357.         if (glob_list)
  2358.           orig_list = (WORD_LIST *)list_append (glob_list, orig_list);
  2359.         else
  2360.           if (!allow_null_glob_expansion)
  2361.             orig_list =
  2362.               make_word_list (copy_word (tlist->word), orig_list);
  2363.           }
  2364.         else
  2365.           {
  2366.         /* Fix the hi-bits. (This is how we quoted special
  2367.            characters.) */
  2368.         register char *t = tlist->word->word;
  2369.         dequote_string (t);
  2370.         orig_list = make_word_list (copy_word (tlist->word), orig_list);
  2371.           }
  2372.  
  2373.         free_array (temp_list);
  2374.         temp_list = (char **)NULL;
  2375.  
  2376.         tlist = tlist->next;
  2377.       }
  2378.     dispose_words (new_list);
  2379.     new_list = orig_list;
  2380.       }
  2381.     else
  2382.       {
  2383.     /* Fix the hi-bits. (This is how we quoted special characters.) */
  2384.     register WORD_LIST *wl = new_list;
  2385.     register char *wp;
  2386.     while (wl) {
  2387.       wp = wl->word->word;
  2388.       dequote_string (wp);
  2389.       wl = wl->next;
  2390.     }
  2391.     return (new_list);
  2392.       }
  2393.   }
  2394.   return (WORD_LIST *)(reverse_list (new_list));
  2395. }
  2396.  
  2397. /* Call the glob library to do globbing on PATHNAME.
  2398.    PATHNAME can contain characters with the hi bit set; this indicates
  2399.    that the character is to be quoted.  We quote it here. */
  2400. char **
  2401. shell_glob_filename (pathname)
  2402.      char *pathname;
  2403. {
  2404.   extern char **glob_filename ();
  2405.   register int i, j;
  2406.   char *temp = (char *)alloca (2 * strlen (pathname) + 1);
  2407.  
  2408.   for (i = j = 0; pathname[i]; i++, j++)
  2409.     {
  2410.       if ((unsigned char)pathname[i] > 0x7f)
  2411.     temp[j++] = '\\';
  2412.  
  2413.       temp[j] = DEQUOTE_CHAR (pathname[i]);
  2414.     }
  2415.   temp[j] = '\0';
  2416.  
  2417.   return (glob_filename (temp));
  2418. }
  2419.  
  2420. /*************************************************
  2421.  *                         *
  2422.  *    Functions to manage special variables     *
  2423.  *                         *
  2424.  *************************************************/
  2425.  
  2426. /* An alist of name.function for each special variable.  Most of the functions
  2427.    don't do much, and in fact, this would be faster with a switch statement,
  2428.    but by the end of this file, I am sick of switch statements. */
  2429.  
  2430. /* The functions that get called. */
  2431. int
  2432.   sv_path (),
  2433. /**
  2434.  ** (sjk)++ Remove all host/mail references on the Atari ST
  2435.  **/
  2436. #if !defined(atarist)
  2437.              sv_mail (),
  2438. #endif 
  2439.   sv_terminal (), sv_histsize (), sv_histfilesize (),
  2440.   sv_uids (), sv_ignoreeof (), sv_glob_dot_filenames (), sv_histchars (),
  2441.   sv_nolinks (), 
  2442. /**
  2443.  ** (sjk)++ Remove all host/mail references on the Atari ST
  2444.  **/
  2445. #if !defined(atarist)
  2446.   sv_hostname_completion_file (), 
  2447. #endif 
  2448.   sv_history_control (),
  2449.   sv_noclobber (), sv_allow_null_glob_expansion (), sv_optind (), sv_opterr ();
  2450.  
  2451. #if defined (JOB_CONTROL)
  2452. extern int sv_notify ();
  2453. #endif
  2454.  
  2455. struct name_and_function {
  2456.   char *name;
  2457.   Function *function;
  2458. } special_vars[] = {
  2459.   { "PATH", sv_path },
  2460. /**
  2461.  ** (sjk)++ Remove all host/mail references on the Atari ST
  2462.  **/
  2463. #if !defined(atarist)
  2464.   { "MAIL", sv_mail },
  2465.   { "MAILPATH", sv_mail },
  2466.   { "MAILCHECK", sv_mail },
  2467. #endif
  2468.   { "TERMCAP", sv_terminal },
  2469.   { "TERM", sv_terminal },
  2470.   { "HISTSIZE", sv_histsize },
  2471.   { "HISTFILESIZE", sv_histfilesize },
  2472.   { "EUID", sv_uids},
  2473.   { "UID", sv_uids},
  2474.   { "IGNOREEOF", sv_ignoreeof },
  2475.   { "ignoreeof", sv_ignoreeof },
  2476. #if defined (GETOPTS)
  2477.   { "OPTIND", sv_optind },
  2478.   { "OPTERR", sv_opterr },
  2479. #endif /* GETOPTS */
  2480. #ifdef JOB_CONTROL
  2481.   { "notify", sv_notify },
  2482. #endif  /* JOB_CONTROL */
  2483.   { "glob_dot_filenames", sv_glob_dot_filenames },
  2484.   { "allow_null_glob_expansion", sv_allow_null_glob_expansion },
  2485.   { "histchars", sv_histchars },
  2486.   { "nolinks", sv_nolinks },
  2487. /**
  2488.  ** (sjk)++ Remove all host/mail references on the Atari ST
  2489.  **/
  2490. #if !defined(atarist)
  2491.   { "hostname_completion_file", sv_hostname_completion_file },
  2492. #endif
  2493.   { "history_control", sv_history_control },
  2494.   { "noclobber", sv_noclobber },
  2495.   { (char *)0x00, (Function *)0x00 }
  2496. };
  2497.  
  2498. /* The variable in NAME has just had its state changed.  Check to see if it
  2499.    is one of the special ones where something special happens. */
  2500. stupidly_hack_special_variables (name)
  2501.      char *name;
  2502. {
  2503.   int i = 0;
  2504.  
  2505.   while (special_vars[i].name)
  2506.     {
  2507.       if (STREQ (special_vars[i].name, name))
  2508.     {
  2509.       (*(special_vars[i].function)) (name);
  2510.       return;
  2511.     }
  2512.       i++;
  2513.     }
  2514. }
  2515.  
  2516. /* Set/unset noclobber. */
  2517. sv_noclobber (name)
  2518.      char *name;
  2519. {
  2520.   extern int noclobber;
  2521.  
  2522.   if (find_variable (name))
  2523.     noclobber = 1;
  2524.   else
  2525.     noclobber = 0;
  2526. }
  2527.  
  2528. /* What to do just after the PATH variable has changed. */
  2529. sv_path (name)
  2530.      char *name;
  2531. {
  2532.   /* hash -r */
  2533.   WORD_LIST *args;
  2534.  
  2535.   args = make_word_list (make_word ("-r"), NULL);
  2536.   hash_builtin (args);
  2537.   dispose_words (args);
  2538. }
  2539.  
  2540. /* What to do just after one of the MAILxxxx variables has changed.  NAME
  2541.    is the name of the variable.  */
  2542. /**
  2543.  ** (sjk)++ Remove all host/mail references on the Atari ST
  2544.  **/
  2545. #if !defined(atarist)
  2546. sv_mail (name)
  2547.      char *name;
  2548. {
  2549.   /* If the time interval for checking the files has changed, then
  2550.      reset the mail timer.  Otherwise, one of the pathname vars
  2551.      to the users mailbox has changed, so rebuild the array of
  2552.      filenames. */
  2553.   if (strcmp (name, "MAILCHECK") == 0)
  2554.     reset_mail_timer ();
  2555.   else
  2556.     {
  2557.       if ((strcmp (name, "MAIL") == 0) || (strcmp (name, "MAILPATH") == 0))
  2558.     {
  2559.       free_mail_files ();
  2560.       remember_mail_dates ();
  2561.     }
  2562.     }
  2563. }
  2564. #endif 
  2565.  
  2566. /* What to do just after one of the TERMxxx variables has changed.
  2567.    If we are an interactive shell, then try to reset the terminal
  2568.    information in readline. */
  2569. sv_terminal (name)
  2570.      char *name;
  2571. {
  2572.   extern int interactive;
  2573.  
  2574.   if (interactive)
  2575.     rl_reset_terminal (get_string_value ("TERM"));
  2576. }
  2577.  
  2578. /* What to do after the HISTSIZE variable changes.
  2579.    If there is a value for this variable (and it is numeric), then stifle
  2580.    the history.  Otherwise, if there is NO value for this variable,
  2581.    unstifle the history. */
  2582. sv_histsize (name)
  2583.      char *name;
  2584. {
  2585.   char *temp = get_string_value (name);
  2586.  
  2587.   if (temp)
  2588.     {
  2589.       int num;
  2590.       if (sscanf (temp, "%d", &num) == 1)
  2591.     {
  2592.       extern int history_lines_this_session;
  2593.  
  2594.       stifle_history (num);
  2595.       if (history_lines_this_session > where_history ())
  2596.         history_lines_this_session = where_history ();
  2597.     }
  2598.     }
  2599.   else
  2600.     unstifle_history ();
  2601. }
  2602.  
  2603. /* What to do if the HISTFILESIZE variable changes. */
  2604. sv_histfilesize (name)
  2605.      char *name;
  2606. {
  2607.   char *temp = get_string_value (name);
  2608.  
  2609.   if (temp)
  2610.     {
  2611.       extern int history_lines_in_file;
  2612.       int num;
  2613.       if (sscanf (temp, "%d", &num) == 1)
  2614.     {
  2615.       history_truncate_file (get_string_value ("HISTFILE"), num);
  2616.       if (num <= history_lines_in_file)
  2617.         history_lines_in_file = num;
  2618.     }
  2619.     }
  2620. }
  2621.  
  2622. /* A nit for picking at history saving.
  2623.    Value of 0 means save all lines parsed by the shell on the history.
  2624.    Value of 1 means save all lines that do not start with a space.
  2625.    Value of 2 means save all lines that do not match the last line saved. */
  2626. int history_control = 0;
  2627.  
  2628. /* What to do after the HISTORY_CONTROL variable changes. */
  2629. sv_history_control (name)
  2630.      char *name;
  2631. {
  2632.   char *temp = get_string_value (name);
  2633.  
  2634.   history_control = 0;
  2635.  
  2636.   if (temp && *temp)
  2637.     {
  2638.       if (strcmp (temp, "ignorespace") == 0)
  2639.     history_control = 1;
  2640.       else if (strcmp (temp, "ignoredups") == 0)
  2641.     history_control = 2;
  2642.     }
  2643. }
  2644.  
  2645. /* If the variable exists, then the value of it can be the number
  2646.    of times we actually ignore the EOF.  The default is small,
  2647.    (smaller than csh, anyway). */
  2648. sv_ignoreeof (name)
  2649.      char *name;
  2650. {
  2651.   extern int eof_encountered, eof_encountered_limit;
  2652.   char *temp = get_string_value (name);
  2653.   int new_limit;
  2654.  
  2655.   eof_encountered = 0;
  2656.  
  2657.   if (temp && (sscanf (temp, "%d", &new_limit) == 1))
  2658.     eof_encountered_limit = new_limit;
  2659.   else
  2660.     eof_encountered_limit = 10; /* csh uses 26. */
  2661. }
  2662.  
  2663. /* Control whether * matches .files in globbing.  Yechh. */
  2664.  
  2665. sv_glob_dot_filenames (name)
  2666.      char *name;
  2667. {
  2668.   extern int noglob_dot_filenames;
  2669.  
  2670.   noglob_dot_filenames = !(find_variable (name));
  2671. }
  2672.  
  2673. /* Setting/unsetting of the history expansion character. */
  2674. char old_history_expansion_char = '!';
  2675. char old_history_comment_char = '#';
  2676. char old_history_subst_char = '^';
  2677.  
  2678. sv_histchars (name)
  2679.      char *name;
  2680. {
  2681.   extern char history_expansion_char;
  2682.   extern char history_comment_char;
  2683.   extern char history_subst_char;
  2684.   char *temp = get_string_value (name);
  2685.  
  2686.   if (temp)
  2687.     {
  2688.       old_history_expansion_char = history_expansion_char;
  2689.       history_expansion_char = *temp;
  2690.  
  2691.       if (temp[1])
  2692.     {
  2693.       old_history_subst_char = history_subst_char;
  2694.       history_subst_char = temp[1];
  2695.  
  2696.       if (temp[2])
  2697.         {
  2698.           old_history_comment_char = history_comment_char;
  2699.           history_comment_char = temp[2];
  2700.         }
  2701.     }
  2702.     }
  2703.   else
  2704.     {
  2705.       history_expansion_char = '!';
  2706.       history_subst_char = '^';
  2707.       history_comment_char = '#';
  2708.     }
  2709. }
  2710.  
  2711. #ifdef JOB_CONTROL
  2712. /* Job notification feature desired? */
  2713. sv_notify (name)
  2714.      char *name;
  2715. {
  2716.   extern int asynchronous_notification;
  2717.  
  2718.   if (get_string_value (name))
  2719.     asynchronous_notification = 1;
  2720.   else
  2721.     asynchronous_notification = 0;
  2722. }
  2723. #endif  /* JOB_CONTROL */
  2724.  
  2725. /* If the variable `nolinks' exists, it specifies that symbolic links are
  2726.    not to be followed in `cd' commands. */
  2727. sv_nolinks (name)
  2728.      char *name;
  2729. {
  2730.   extern int follow_symbolic_links;
  2731.  
  2732.   follow_symbolic_links = !find_variable (name);
  2733. }
  2734.  
  2735. /* Don't let users hack the user id variables. */
  2736. sv_uids (name)
  2737.      char *name;
  2738. {
  2739.   int uid = getuid ();
  2740.   int euid = geteuid ();
  2741.   char buff[10];
  2742.   register SHELL_VAR *v;
  2743.  
  2744.   sprintf (buff, "%d", uid);
  2745.   v = find_variable ("UID");
  2746.   if (v)
  2747.     v->attributes &= ~att_readonly;
  2748.  
  2749.   v = bind_variable ("UID", buff);
  2750.   v->attributes |= (att_readonly | att_integer);
  2751.  
  2752.   sprintf (buff, "%d", euid);
  2753.   v = find_variable ("EUID");
  2754.   if (v)
  2755.     v->attributes &= ~att_readonly;
  2756.  
  2757.   v = bind_variable ("EUID", buff);
  2758.   v->attributes |= (att_readonly | att_integer);
  2759. }
  2760.  
  2761. /**
  2762.  ** (sjk)++ Remove all host/mail references on the Atari ST
  2763.  **/
  2764. #if !defined(atarist)
  2765. sv_hostname_completion_file (name)
  2766.      char *name;
  2767. {
  2768.   extern int hostname_list_initialized;
  2769.  
  2770.   hostname_list_initialized = 0;
  2771. }
  2772. #endif 
  2773.  
  2774. sv_allow_null_glob_expansion (name)
  2775.      char *name;
  2776. {
  2777.   allow_null_glob_expansion = (int)find_variable (name);
  2778. }
  2779.  
  2780. #if defined (GETOPTS)
  2781. sv_optind (name)
  2782.      char *name;
  2783. {
  2784.   char *tt = get_string_value ("OPTIND");
  2785.   int s;
  2786.  
  2787.   if (!tt || !*tt)
  2788.     s = 1;
  2789.   else
  2790.     {
  2791.       if ((s = atoi (tt)) <= 0)
  2792.     s = 1;
  2793.     }
  2794.   getopts_reset (s);
  2795. }
  2796.  
  2797. int
  2798. sv_opterr (name)
  2799.      char *name;
  2800. {
  2801.   char *tt = get_string_value ("OPTERR");
  2802.   int s = 1;
  2803.   extern int opterr;
  2804.  
  2805.   if (tt)
  2806.     s = atoi (tt);
  2807.   opterr = s;
  2808.   return (0);
  2809. }
  2810. #endif /* GETOPTS */
  2811.